我把问烂了的⭐MyBatis面试题⭐总结了一下(带答案,万字总结,精心打磨,建议收藏) |
您所在的位置:网站首页 › 双向映射 数据结构 › 我把问烂了的⭐MyBatis面试题⭐总结了一下(带答案,万字总结,精心打磨,建议收藏) |
💂 个人主页: Java程序鱼 💬 如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)和订阅专栏 👤 微信号:hzy1014211086,想加入技术交流群的小伙伴可以加我好友,群里会分享学习资料、学习方法 序号内容链接地址1Java基础知识面试题https://blog.csdn.net/qq_35620342/article/details/1196364362Java集合容器面试题https://blog.csdn.net/qq_35620342/article/details/1199472543Java并发编程面试题https://blog.csdn.net/qq_35620342/article/details/1199772244Java异常面试题https://blog.csdn.net/qq_35620342/article/details/1199770515JVM面试题https://blog.csdn.net/qq_35620342/article/details/1199489896Java Web面试题https://blog.csdn.net/qq_35620342/article/details/1196421147Spring面试题https://blog.csdn.net/qq_35620342/article/details/1199565128Spring MVC面试题https://blog.csdn.net/qq_35620342/article/details/1199655609Spring Boot面试题https://blog.csdn.net/qq_35620342/article/details/12033371710MyBatis面试题https://blog.csdn.net/qq_35620342/article/details/11995654111Spring Cloud面试题待分享12Redis面试题https://blog.csdn.net/qq_35620342/article/details/11957502013MySQL数据库面试题https://blog.csdn.net/qq_35620342/article/details/11993088714RabbitMQ面试题待分享15Dubbo面试题待分享16Linux面试题待分享17Tomcat面试题待分享18ZooKeeper面试题待分享19Netty面试题待分享20数据结构与算法面试题待分享 文章目录 1.MyBatis是什么?2.ORM是什么3.为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?4.传统JDBC开发存在的问题5.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?6.MyBatis与Hibernate7.Mybatis优缺点8.MyBatis框架适用场景9.MyBatis编程步骤是什么样的?10.请说说MyBatis的工作原理11.MyBatis功能架构12.MyBatis的框架架构设计是怎么样的13.为什么需要预编译14.Mybatis都有哪些Executor执行器?它们之间的区别是什么?15.Mybatis中如何指定使用哪一种Executor执行器?16.Mybatis延迟加载17.#{}和${}的区别18.模糊查询like语句该怎么写19.在mapper中如何传递多个参数20.Mybatis如何执行批量操作21.如何获取生成的主键22.当实体类中的属性名和表中的字段名不一样 ,怎么办23.Mapper 编写有哪几种方式?24.MyBatis接口绑定的几种方式25.使用MyBatis的mapper接口调用时有哪些要求?26.通常一个mapper.XML对应一个DAO接口,DAO是否可以重载?27.MyBatis不同映射文件中的id是否可以重复?28.简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?29.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?30.Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?31.MyBatis映射文件中A标签引用B标签,如果B标签在A的后面定义,可以吗?32.MyBatis实现一对一,一对多有几种方式,怎么操作的?33.Mybatis是否可以映射Enum枚举类?34.Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?35.Mybatis是如何进行分页的?36.简述Mybatis的插件运行原理,以及如何编写一个插件。37.Mybatis缓存机制 1.MyBatis是什么?MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。 2.ORM是什么ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中。 3.为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。 而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。 4.传统JDBC开发存在的问题JDBC是Java连接关系数据库的底层API,利用JDBC开发持久层存在诸多问题,而MyBatis正是为了解决JDBC的以下问题而生的。 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。使用PreparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。 5.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?1、数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。 解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库连接。 2、Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。 3、使用PreparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。 解决: Mybatis自动将java对象映射至sql语句。 4、对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。 解决:Mybatis自动将sql执行结果映射至java对象。 6.MyBatis与HibernateMyBatis和Hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句,不过Mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。 MyBatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。 Hibernate对象/关系映射能力强,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用Hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。 7.Mybatis优缺点优点 与传统的数据库访问技术相比,ORM有以下优点: 基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护能够与Spring很好的集成缺点 SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库 8.MyBatis框架适用场景 MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。 9.MyBatis编程步骤是什么样的?(1)获取SqlSessionFactory对象 解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession; 注意:【MappedStatement】:代表一个增删改查的详细信息 (2)获取SqlSession对象 返回一个DefaultSqlSession对象,包含Executor和Configuration; 这一步会创建Executor; (3)获取接口的代理对象(MapperProxy) getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象,代理对象里包含了DefaultSqlSession(Executor) (4)执行增删改查方法 (5)关闭会话 10.请说说MyBatis的工作原理在学习 MyBatis 程序之前,需要了解一下 MyBatis 工作原理,以便于理解程序。MyBatis 的工作原理如下图
这张图从上往下看。MyBatis的初始化,会从mybatis-config.xml配置文件,解析构造成Configuration这个类,就是图中的红框。 (1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。 (2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。 (3)SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。 (4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。 13.为什么需要预编译1.定义: SQL 预编译指的是数据库驱动在发送 SQL 语句和参数给 DBMS 之前对 SQL 语句进行编译,这样 DBMS 执行 SQL 时,就不需要重新编译。 2.为什么需要预编译 JDBC 中使用对象 PreparedStatement 来抽象预编译语句,使用预编译。预编译阶段可以优化 SQL 的执行。预编译之后的 SQL 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的SQL,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。同时预编译语句对象可以重复利用。把一个 SQL 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个SQL,可以直接使用这个缓存的 PreparedState 对象。Mybatis默认情况下,将对所有的 SQL 进行预编译。 14.Mybatis都有哪些Executor执行器?它们之间的区别是什么? SimpleExecutor是最简单的执行器,根据对应的sql直接执行即可,不会做一些额外的操作;BatchExecutor执行器,顾名思义,通过批量操作来优化性能。通常需要注意的是批量更新操作,由于内部有缓存的实现,使用完成后记得调用flushStatements来清除缓存。ReuseExecutor 可重用的执行器,重用的对象是Statement,也就是说该执行器会缓存同一个sql的Statement,省去Statement的重新创建,优化性能。内部的实现是通过一个HashMap来维护Statement对象的。由于当前Map只在该session中有效,所以使用完成后记得调用flushStatements来清除Map。 15.Mybatis中如何指定使用哪一种Executor执行器?在Mybatis配置文件中,在设置(settings)可以指定默认的ExecutorType执行器类型,也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型参数,如SqlSession openSession(ExecutorType execType)。 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 16.Mybatis延迟加载在实际使用中,我们会经常性的涉及到多表联合查询,但是有时候,并不会立即用到所有的查询结果,我来举两个例子: 例如,查询一批笔记本电脑的进货明细,而不直接展示每列明细对应电脑配置或者价格等的详细信息,等到用户需要取出某笔记本相关的详细信息的时候,再进行单表查询再例如 ,银行中,某个用户拥有50个账户(打比方),再我们查询这个而用户的信息,这个用户下所有账户的详细信息很显然,在使用的时候再查询才是比较合理的针对这样一种情况,延迟加载这一种机制就出现了,延迟加载(懒加载)顾名思义,就是对某种信息推迟加载,这样的技术也就帮助我们实现了 “按需查询” 的机制,在一对多,或者多对多的情况下 既然提到了延迟加载,当然顺便提一句立即加载,它的含义就是不管是否用户需要,一调用,则马上查询,这种方式,适合与多对一,或者一对一的情况下。 首先,配置基本的环境,然后我们首先在数据库准备两张表 User表 CREATE TABLE USER ( `id` INT(11)NOT NULL AUTO_INCREMENT, `username` VARCHAR(32) NOT NULL COMMENT '用户名', `telephone` VARCHAR(11) NOT NULL COMMENT '手机', `birthday` DATETIME DEFAULT NULL COMMENT '生日', `gender` CHAR(1) DEFAULT NULL COMMENT '性别', `address` VARCHAR(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8;Account表 CREATE TABLE `account` ( `ID` int(11) NOT NULL COMMENT '编号', `UID` int(11) default NULL COMMENT '用户编号', `MONEY` double default NULL COMMENT '金额', PRIMARY KEY (`ID`), KEY `FK_Reference_8` (`UID`), CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;然后分别创建出其对应的实体类 User类 public class User implements Serializable { private Integer id; private String username; private String telephone; private Date birthday; private String gender; private String address; //一对多关系映射,主表实体应该包含从表实体的集合引用 private List accounts; ...... 请补充 get set 和 toString 方法 }Account类 public class Account implements Serializable { private Integer id; private Integer uid; private Double money; //从表实体应该包含一个主表实体的对象引用 private User user; ...... 请补充 get set 和 toString 方法 }UserMapper.xml SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT OUTER JOIN account a on u.id = a.uid; select * from user where id = #{uid}两个接口中创建对应方法 public interface AccountMapper { /** * 查询所有账户 * @return */ List findAll(); } public interface UserMapper { /** * 查询所有用户信息,同时显示出该用户下的所有账户 * * @return */ List findAll(); /** * 根据id查询用户信息 * @param userId * @return */ User findById(Integer userId); }延迟加载代码实现 首先,给大家演示一下,我们之前一对一查询用户的方式,同时会将用户对应所有的账户信息,也查询出来 /** * 测试查询所有 */ @Test public void testFindAll() { List users= userMapper.findAll(); for (User user : users) { System.out.println("---------------------"); System.out.println(user); System.out.println(user.getAccounts()); } }效果: 这种方式是通过 SQL 语句,以及resultMap将 用户和账户的信息同时查询出来 那么如何实现我们上面所说的延迟加载呢? 这次我们选择 查询账户,然后延迟加载用户的信息 修改AccountMapper.xml 首先需要修改的就是账户的映射配置文件,可以看到我们在查询时,依旧定义了一个 resultMap 先封装了 Account ,然后通过association 进行关联 User,其中使用的就是 select 和 column 实现了延迟加载用户信息 select 用来指定延迟加载所需要执行的 SQL 语句,也就是指定 某个SQL映射文件中的某个select标签对的 id,在这里我们指定了用户中通过id查询信息的方法column 是指关联的用户信息查询的列,在这里也就是关联的用户的主键即,id SELECT * FROM account第一次测试代码 我们只执行一下账户的查询所有方法,看一下,是否能够实现我们的效果 @Test public void testFindAll(){ List accounts = accountMapper.findAll(); }执行效果 这是因为,我们在测试方法之前,需要开启延迟加载功能 延迟加载功能 经过查阅文档,我们知道了,如果想要开始延迟加载功能,就需要在总配置文件 SqlMapConfig.xml 中配置 setting 属性,也就是将延迟加载 lazyLoadingEnable 的开关设置成 teue ,由于是按需加载,所以还需要将积极加载修改为消极加载,也就是将 aggressiveLazyLoading 改为 false 当然,由于我这里导入的 MyBatis 版本为 3.4.5 所以这个值默认就是 false 实际上不用设置也可以,不过我们还是写出来 注意:如果有使用typeAliases配置别名的话一定要将 typeAliases 标签放在后面 再次测试 仍然只执行查询方法 @Test public void testFindAll(){ List accounts = accountMapper.findAll(); }执行效果 这一次果然只执行了一条查询 account 的命令 那么当用户想要查看到,每个账户对应下的用户的时候呢?这也就是按需查询,只需要在测试时,加入对应获取方法就可以了 @Test public void testFindAll(){ List accounts = accountMapper.findAll(); for (Account account : accounts){ System.out.println("----------------------------"); System.out.println(account); System.out.println(account.getUser()); } }执行一下 #{} 是预编译处理,像传进来的数据会加个" "(#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号) 就 是 字 符 串 替 换 。 直 接 替 换 掉 占 位 符 。 {} 就是字符串替换。直接替换掉占位符。 就是字符串替换。直接替换掉占位符。方式一般用于传入数据库对象,例如传入表名. 使用 ${} 的话会导致 sql 注入。什么是 SQL 注入呢?比如 select * from user where id = ${value} value 应该是一个数值吧。然后如果对方传过来的是 001 and name = tom。这样不就相当于多加了一个条件嘛?把SQL语句直接写进来了。如果是攻击性的语句呢?001;drop table user,直接把表给删了 所以为了防止 SQL 注入,能用 #{} 的不要去用 ${} 如果非要用 ${} 的话,那要注意防止 SQL 注入问题,可以手动判定传入的变量,进行过滤,一般 SQL 注入会输入很长的一条 SQL 语句 18.模糊查询like语句该怎么写方式1:$ 这种方式,简单,但是无法防止SQL注入,所以不推荐使用 LIKE '%${name}%'方式2:# LIKE "%"#{name}"%"方式3:字符串拼接 AND name LIKE CONCAT(CONCAT('%',#{name},'%'))方式4:bind标签 SELECT * FROM test_student age ${compare} #{age} AND name LIKE #{pattern1} AND address LIKE #{pattern2} ORDER BY id方式5:java代码里写 param.setUsername("%CD%"); 在 java 代码中传参的时候直接写上 AND username LIKE #{username}然后 mapper 里面直接写 #{} 就可以了 19.在mapper中如何传递多个参数方法一:使用map接口传递参数 严格来说,map适用几乎所有场景,但是我们用得不多。原因有两个:首先,map是一个键值对应的集合,使用者要通过阅读它的键,才能明了其作用;其次,使用map不能限定其传递的数据类型,因此业务性质不强,可读性差,使用者要读懂代码才能知道需要传递什么参数给它,所以不推荐用这种方式传递多个参数。 public List findRolesByMap(Map parameterMap); select id, role_name as roleName, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note}, '%')方法二:使用注解传递多个参数 MyBatis为开发者提供了一个注解@Param(org.apache.ibatis.annotations.Param),可以通过它去定义映射器的参数名称,使用它可以得到更好的可读性 这个时候需要修改映射文件的代码,此时并不需要给出parameterType属性,让MyBatis自动探索便可以了 使可读性大大提高,使用者也方便了,但是这会带来一个麻烦。如果SQL很复杂,拥有大于10个参数,那么接口方法的参数个数就多了,使用起来就很不容易,不过不必担心,MyBatis还提供传递Java Bean的形式。 public List findRolesByAnnotation(@Param("roleName") String rolename, @Param("note") String note); select id, role_name as roleName, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note}, '%')方法三:通过Java Bean传递多个参数 public List findRolesByBean(RoleParams roleParam); select id, role_name as roleName, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note}, '%')方法四:混合使用 在某些情况下可能需要混合使用几种方法来传递参数。举个例子,查询一个角色,可以通过角色名称和备注进行查询,与此同时还需要支持分页 public List findByMix(@Param("params") RoleParams roleParams, @Param("page") PageParam PageParam); select id, role_name as roleName, note from t_role where role_name like concat('%', #{params.roleName}, '%') and note like concat('%', #{params.note}, '%') limit #{page.start}, #{page.limit} 20.Mybatis如何执行批量操作Mybatis常会出现批量操作,如批量查询,批量插入,批量修改(replace into)。批量操作要比循环执行效率提升很多,这里对mybatis的批量操作做一个总结讲解。 (1)Foreach foreach:foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有 item,index,collection,open,separator,close。它是批量操作的核心标签,下面都是foreach在不同场景的应用和写法。 List select id, accid, key1, key1createtime key1CreateTime, key2, key2createtime key2CreateTime from m_acc_keys where accid in #{item}注意:你可以传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list”作为键,而数组实例将会以“array”作为键。 List 这是一个批量保存(插入或修改)的例子 replace into xx (id, c1,c2) values (#{it.id},#{it.c1},#{it.c2})replace:会根据主键和唯一索引判断该记录是否存在,存在就删除在插入(修改),不存在就插入(insert)。 (2)数组 还是一个查询的例子 public List selectByIds(String[] ids); where c.id in #{id}(3)多重循环 colids和proids是两个平级的数据。 insert into b_column_programme(columnId, programmeId) values (#{colid}, #{proid})(4)批量插入id自增长 Mybatis在版本3.4.x以上支持批量插入绑定自增长id,常用版本3.4.1。 对应的maven支持 org.mybatis mybatis 3.4.1 org.mybatis mybatis-spring 1.3.1Mapper.xml写法 insert into xx (c1,c2) values (#{it.c1},#{it.c2}) 21.如何获取生成的主键MySQL:Mapper 文件 insert 语句设置 useGeneratedKeys="true" keyProperty="id"Oracle:Mapper 文件 insert 语句增加 select xxx_SEQ.nextval from dual 22.当实体类中的属性名和表中的字段名不一样 ,怎么办第1种: 通过在查询的SQL语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。 select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};第2种: 通过来映射字段名和实体类属性名的一一对应的关系。 select * from orders where order_id=#{id} 23.Mapper 编写有哪几种方式?第一种:接口实现类继承 SqlSessionDaoSupport:使用此种方法需要编写mapper 接口,mapper 接口实现类、mapper.xml 文件。 (1)在 sqlMapConfig.xml 中配置 mapper.xml 的位置 (2)定义 mapper 接口 (3)实现类集成 SqlSessionDaoSupport mapper 方法中可以 this.getSqlSession()进行数据增删改查。 (4)spring 配置 第二种:使用 org.mybatis.spring.mapper.MapperFactoryBean: (1)在 sqlMapConfig.xml 中配置 mapper.xml 的位置,如果 mapper.xml 和mappre 接口的名称相同且在同一个目录,这里可以不用配置 (2)定义 mapper 接口: (3)mapper.xml 中的 namespace 为 mapper 接口的地址 (4)mapper 接口中的方法名和 mapper.xml 中的定义的 statement 的 id 保持一致 (5)Spring 中定义 第三种:使用 mapper 扫描器: (1)mapper.xml 文件编写: mapper.xml 中的 namespace 为 mapper 接口的地址; mapper 接口中的方法名和 mapper.xml 中的定义的 statement 的 id 保持一致; 如果将 mapper.xml 和 mapper 接口的名称保持一致则不用在 sqlMapConfig.xml中进行配置。 (2)定义 mapper 接口: 注意 mapper.xml 的文件名和 mapper 的接口名称保持一致,且放在同一个目录 (3)配置 mapper 扫描器: (4)使用扫描器后从 spring 容器中获取 mapper 的实现对象。 24.MyBatis接口绑定的几种方式接口绑定有两种方式 (1)使用注解,在接口的方法上面添加@Select@Update等注解,里面写上对应的SQL语句进行SQL语句的绑定。 (2)通过映射文件xml方式进行绑定,指定xml映射文件中的namespace对应的接口的全路径名 什么时候用注解绑定?什么时候用xml绑定? 当SQL语句比较简单的时候,使用注解绑定就可以了,当SQL语句比较复杂的话,使用xml方式绑定,一般用xml方式绑定比较多 25.使用MyBatis的mapper接口调用时有哪些要求?Mapper接口方法名和mapper.xml中定义的每个sql的id相同。 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。 Mapper.xml文件中的namespace即是mapper接口的类路径。 26.通常一个mapper.XML对应一个DAO接口,DAO是否可以重载?答:不能重载,方法名对应的 mapper.xml 文件里的一个 id,这个与方法名对应,系统会根据 namespace+id 找到对应的方法对应。 Dao 接口即 Mapper 接口。接口的全限名,就是映射文件中的 namespace 的值;接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值;接口方法内的参数,就是传递给 sql 的参数。Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个标签,都会被解析为一个MapperStatement 对象。 举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到 namespace 为 com.mybatis3.mappers.StudentDao 下面 id 为findStudentById 的 MapperStatement。 Mapper 接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而执行 MapperStatement 所代表的 sql,然后将 sql 执行结果返回。 27.MyBatis不同映射文件中的id是否可以重复?可以重复,但是需要映射文件的namespace不同 不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复。 原因就是 namespace+id 是作为 Map的 key使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。 有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。 28.简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?答:Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。在Xml映射文件中,标签会被解析为ParameterMap对象,其每个子元素会被解析为ParameterMapping对象。标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象。每一个、、、标签均会被解析为MappedStatement对象,标签内的sql会被解析为BoundSql对象。 29.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?第一种是使用标签,逐一定义列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。 有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。 30.Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?还有很多其他的标签,、、、、,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策略标签。 31.MyBatis映射文件中A标签引用B标签,如果B标签在A的后面定义,可以吗?虽然 Mybatis 解析 Xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可以定义在任何地方,Mybatis 都可以正确识别。 原理: Mybatis 解析 A 标签时,发现引用了 B 标签,未解析到 B 标签,此时会把 A 标签标记为未解析状态; 继续解析下面内容,把剩下解析完之后,再解析标记为未解析的标签; 此时已解析到 B 标签,此时再解析A标签时,B标签已经存在,A 标签也就顺利解析完成。 32.MyBatis实现一对一,一对多有几种方式,怎么操作的?有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在resultMap里面的association,collection节点配置一对一,一对多的类就可以完成 嵌套查询是先查一个表,根据这个表里面的结果的外键id,去再另外一个表里面查询数据,也是通过配置association,collection,但另外一个表的查询通过select节点配置。 33.Mybatis是否可以映射Enum枚举类?Mybatis可以映射枚举类,不单可以映射枚举类,Mybatis可以映射任何对象到表的一列上。映射方式为自定义一个TypeHandler,实现TypeHandler的setParameter()和getResult()接口方法。 TypeHandler有两个作用,一是完成从javaType至jdbcType的转换,二是完成jdbcType至javaType的转换,体现为setParameter()和getResult()两个方法,分别代表设置sql问号占位符参数和获取列查询结果。 34.Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。 其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。 35.Mybatis是如何进行分页的?(1)原始方法,使用 limit,需要自己处理分页逻辑: 对于 mysql 数据库可以使用 limit ,如: select * from table limit 5; --返回前5行 select * from table limit 0,5; --同上,返回前5行 select * from table limit 5,10; --返回6-15行对于 oracle 数据库可以使用 rownum ,如:从表Sys_option(主键为sys_id)中从第10条记录开始检索20条记录,语句如下: SELECT * FROM (SELECT ROWNUM R,t1.* From Sys_option where rownum < 30 ) t2 Where t2.R >= 10(2)拦截StatementHandler,其实质还是在最后生成limit语句 (3)使用PageHelper插件,这是目前比较常见的方法 36.简述Mybatis的插件运行原理,以及如何编写一个插件。Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。 实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。 37.Mybatis缓存机制缓存机制减轻数据库压力,提高数据库性能 mybatis的缓存分为两级:一级缓存、二级缓存 (1)一级缓存: 一级缓存为 sqlsesson 缓存,缓存的数据只在 SqlSession 内有效。在操作数据库的时候需要先创建 SqlSession 会话对象,在对象中有一个 HashMap 用于存储缓存数据,此 HashMap 是当前会话对象私有的,别的 SqlSession 会话对象无法访问。 具体流程: 第一次执行 select 完毕会将查到的数据写入 SqlSession 内的 HashMap 中缓存起来 第二次执行 select 会从缓存中查数据,如果 select 同传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率 注意: 1、如果 SqlSession 执行了 DML 操作(insert、update、delete),并 commit 了,那么 mybatis 就会清空当前 SqlSession 缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现差异 2、当一个 SqlSession 结束后那么他里面的一级缓存也就不存在了, mybatis 默认是开启一级缓存,不需要配置 3、 mybatis 的缓存是基于 [namespace:sql语句:参数] 来进行缓存的,意思就是, SqlSession 的 HashMap 存储缓存数据时,是使用 [namespace:sql:参数] 作为 key ,查询返回的语句作为 value 保存的 (2)二级缓存: 二级缓存是 mapper 级别的缓存,也就是同一个 namespace 的 mapper.xml ,当多个 SqlSession 使用同一个 Mapper 操作数据库的时候,得到的数据会缓存在同一个二级缓存区域 二级缓存默认是没有开启的。需要在 setting 全局参数中配置开启二级缓存 开启二级缓存步骤: 1、conf.xml 配置全局变量开启二级缓存 默认是false:关闭二级缓存2、在 userMapper.xml 中配置 当前mapper下所有语句开启二级缓存 这里配置了一个 LRU 缓存,并每隔60秒刷新,最大存储512个对象,而返回的对象是只读的 若想禁用当前select语句的二级缓存,添加 useCache="false"修改如下: 具体流程: 1.当一个 sqlseesion 执行了一次 select 后,在关闭此 session 的时候,会将查询结果缓存到二级缓存 2.当另一个 sqlsession 执行 select 时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能 注意: 1、如果 SqlSession 执行了 DML 操作(insert、update、delete),并 commit 了,那么 mybatis 就会清空当前 mapper 缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现差异 2、 mybatis 的缓存是基于 [namespace:sql语句:参数] 来进行缓存的,意思就是,SqlSession 的 HashMap 存储缓存数据时,是使用 [namespace:sql:参数] 作为 key ,查询返回的语句作为 value 保存的。 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |